import axios from 'axios'
import router from '@/routers'
import defaultConfig from '@/config'
import { useUserStore } from '@/stores/modules/user'
import { ElMessage, ElNotification } from 'element-plus'
import { showFullScreenLoading, tryHideFullScreenLoading } from '@/components/Loading/fullScreen'
import type { InternalAxiosRequestConfig, AxiosResponse, AxiosRequestConfig, AxiosRequestHeaders } from 'axios'

interface ICodeMessage {
  [propName: number]: string
}

export interface CustomAxiosRequestConfig extends InternalAxiosRequestConfig {
  loading?: boolean
}

const userStore = useUserStore()
const StatusCodeMessage: ICodeMessage = {
  200: '服务器成功返回请求的数据',
  201: '新建或修改数据成功。',
  202: '一个请求已经进入后台排队（异步任务）',
  204: '删除数据成功',
  400: '请求错误(400)',
  401: '未授权，请重新登录(401)',
  403: '拒绝访问(403)',
  404: '请求出错(404)',
  408: '请求超时(408)',
  500: '服务器错误(500)',
  501: '服务未实现(501)',
  502: '网络错误(502)',
  503: '服务不可用(503)',
  504: '网络超时(504)'
}

axios.defaults.baseURL = import.meta.env.VITE_BASE_URL
axios.defaults.timeout = 30 * 1000

// 请求拦截器
axios.interceptors.request.use(
  (config: CustomAxiosRequestConfig) => {
    // 当前请求不需要显示 loading，在 api 服务中通过指定的第三个参数: { loading: false } 来控制
    config.loading && showFullScreenLoading()

    // 配置请求头
    config.headers.set('Authorization', userStore.token)
    return config
  },
  (error) => {
    return Promise.reject(error)
  }
)

// 响应拦截器
axios.interceptors.response.use(
  (response: AxiosResponse) => {
    const { code, msg } = response.data
    tryHideFullScreenLoading()
    switch (code) {
      case 401:
        ElMessage.error(msg || '您尚未登录')
        userStore.setToken('')
        router.replace(defaultConfig.LOGIN_URL)
    }
    return response
  },
  (error) => {
    const response = Object.assign({}, error.response)
    response && ElMessage.error(StatusCodeMessage[response.status] || '系统异常, 请检查网络或联系管理员！')
    return Promise.reject(error)
  }
)

const addTimestampToUrl = (url: string): string => {
  const timestamp = Date.now() // 获取当前时间戳

  // 判断之前url是否有?参数
  return url.includes('?') ? `${url}&t=${timestamp}` : `${url}?t=${timestamp}`
}

const http = <T = unknown>(config: AxiosRequestConfig): Promise<T> => {
  return new Promise((resolve, reject) => {
    axios(config)
      .then((response: AxiosResponse) => {
        const { code, msg, data } = response.data
        switch (code) {
          case 200:
            return resolve(data)
          case 500:
            // 如果错误信息长度过长，使用ElNotification进行提示
            msg.length <= 15
              ? ElMessage.error(msg || '服务器端接口错误')
              : ElNotification({
                  type: 'error',
                  title: '操作失败',
                  message: msg || '服务器接口错误，请联系管理员'
                })
            return reject(msg)
        }
      })
      .catch((error: { message: string }) => reject(error))
  })
}

// get请求
http.get = <T = any>(url: string, params?: object, headers?: Object): Promise<T> => {
  return http<T>({
    method: 'get',
    url: addTimestampToUrl(url),
    data: params,
    headers: (headers || {}) as AxiosRequestHeaders
  })
}

// post请求
http.post = <T = any>(url: string, params?: object, headers?: Object): Promise<T> => {
  return http({
    method: 'post',
    url: addTimestampToUrl(url),
    data: params,
    headers: (headers || {}) as AxiosRequestHeaders
  })
}

// put请求
http.put = <T = any>(url: string, params?: object, headers?: Object): Promise<T> => {
  return http({
    method: 'put',
    url: addTimestampToUrl(url),
    data: params,
    headers: (headers || {}) as AxiosRequestHeaders
  })
}

// delete请求
http.delete = <T = any>(url: string, params?: object, headers?: Object): Promise<T> => {
  return http({
    method: 'delete',
    url: addTimestampToUrl(url),
    data: params,
    headers: (headers || {}) as AxiosRequestHeaders
  })
}
// delete请求
http.download = (url: string, params?: object): Promise<BlobPart> => {
  return http({
    method: 'post',
    url: addTimestampToUrl(url),
    data: params,
    headers: { responseType: 'blob' },
    timeout: 30 * 1000
  })
}

export default http
